
package com.x52im.rbchat.logic.chat_root.targetchoose;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.DynamicDrawableSpan;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.eva.android.ArrayListObservable;
import com.eva.android.ToolKits;
import com.eva.android.widget.DataLoadableActivity;
import com.eva.android.widget.ARecyclerViewAdapter;
import com.eva.android.widget.WidgetUtils;
import com.eva.epc.common.util.CommonUtils;
import com.eva.framework.dto.DataFromServer;
import com.x52im.rainbowchat.http.logic.dto.GroupEntity;
import com.x52im.rainbowchat.http.logic.dto.GroupMemberEntity;
import com.x52im.rainbowchat.im.dto.ChatType;
import com.x52im.rbchat.R;
import com.x52im.rbchat.cache.GroupsProvider;
import com.x52im.rbchat.cache.ImageCacheLoader;
import com.x52im.rainbowchat.http.logic.dto.RosterElementEntity;
import com.x52im.rbchat.logic.alarm.AlarmType;
import com.x52im.rbchat.logic.alarm.model.AlarmDto;
import com.x52im.rbchat.logic.chat_root.face.EmojiUtil;
import com.x52im.rbchat.logic.sns_group.GroupMemberActivity;
import com.x52im.rbchat.network.http.HttpRestHelper;
import com.x52im.rbchat.network.http.async.QueryFriendInfo;
import com.x52im.rbchat.network.http.async.QueryGroupInfo;
import com.x52im.rbchat.utils.IntentFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

/**
 * 目标选择界面（支持选择"最近聊天"、"好友"、"群聊"这些对象）。
 *
 * <p>
 * 目前用于：
 * 1）个人名片消息发送时选择要发送的用户时使用；
 * 2）群名片消息发送时选择要发送的群聊时使用；
 * 3）消息转发功能中选择被转消息接收者时使用。
 *
 * <p>
 * 本界面代码参考自 {@link GroupMemberActivity} ，原本是想对其进行高度提炼并进行重用，但考虑到可维护性（因为更
 * 多不同用途的场景进行重用，会严重加重原类的业务复杂性），因而放弃重用，转而重新维护一个更灵活强大的可重用版本（也
 * 就是本界面），代码好维护总比盲目追求重用要好的多。
 * <p>
 * 日后在进行界面美化时，可以本界面可以与{@link GroupMemberActivity}同步进行优化，因为UI和功能逻辑是相通的。
 *
 * @author JackJiang
 * @since 10.0
 * @see GroupMemberActivity
 */
public class TargetChooseActivity extends DataLoadableActivity
{
    private final static String TAG = TargetChooseActivity.class.getSimpleName();

    private ViewGroup radioButtonsContainer;
    private RadioButton latestChattingRadio, friendRadio, groupRadio, groupMemberRadio;

    /** 【内容UI主组件1】：可供选择的用户列表 */
    private RecyclerView groupListView;
    /** 用户列表Adapter */
    private RecyclerViewLinearAdapter groupListAdapter;

    /** 【内容UI主组件2】：父布局 - 添加好友的父组件引用 */
    private ViewGroup addGroupLL = null;
    /** 按钮：确认 */
    private Button btnOK = null;

    /** 用户列表的数据结构对象. */
    private ArrayList<TargetEntity> staticListData = new ArrayList<>();

    /** 调用者传进来的目标数据源类型。本字段支持位运行进行数据源类型的设置。 */
    private int supportedTargetSource = -1;

    /** 调用者传进来的目标数据源过滤器，供开发者实现数据源的灵活过滤控制（本对象可为空）*/
    private TargetSourceFilter4LatestChatting targetSourceFilter4LatestChatting = null;
    private TargetSourceFilter4Friend targetSourceFilter4Friend = null;
    private TargetSourceFilter4Group targetSourceFilter4Group = null;
    private TargetSourceFilter4GroupMember targetSourceFilter4GroupMembers = null;

    /** 调用者传进来的额外对象，原则上本对象不用在本类中，用于选择目标结束后再回报给调用者，本对象可为空 */
    private Serializable extraObjFromItent = null;
    /** 调用者传进来的群id，仅当支持 {@link TargetSource#groupMember}时需要，且此时不能为空，其它情况请传空 */
    private String gidFromItent = null;

    /** 是否支持"最近聊天"数据源，false表示不支持（UI上将不显示对应的列表和ui） */
    private boolean supportedLatestChattingTargetSource = false;
    /** 是否支持"好友"数据源，false表示不支持（UI上将不显示对应的列表和ui） */
    private boolean supportedFriendTargetSource = false;
    /** 是否支持"群聊"数据源，false表示不支持（UI上将不显示对应的列表和ui） */
    private boolean supportedGroupTargetSource = false;
    /** 是否支持"群成员"数据源，false表示不支持（UI上将不显示对应的列表和ui） */
    private boolean supportedGroupMembersTargetSource = false;
    /** 是否显示选择框 */
    private boolean showCheckBox = true;
    /** 是否支持单选 */
    private boolean singleSelection = false;

    /**
     * {@inheritDoc}
     */
    @Override
    protected void initDataFromIntent()
    {
        //解析从intent中传过来的数据
        ArrayList intentDatas = IntentFactory.parseTargetChooseActivityIntent(getIntent());

        // 支持的目标数据类型
        this.supportedTargetSource = (Integer) intentDatas.get(0);
        this.supportedLatestChattingTargetSource = ((this.supportedTargetSource & TargetSource.latestChatting) == TargetSource.latestChatting);
        this.supportedFriendTargetSource = ((this.supportedTargetSource & TargetSource.friend) == TargetSource.friend);
        this.supportedGroupTargetSource = ((this.supportedTargetSource & TargetSource.group) == TargetSource.group);
        this.supportedGroupMembersTargetSource = ((this.supportedTargetSource & TargetSource.groupMember) == TargetSource.groupMember);

        // 目标数据过滤器（过滤器的目的是让调用者决定哪些数据不显示）
        Object o1 = intentDatas.get(1), o2 = intentDatas.get(2), o3 = intentDatas.get(3)
                , o4 = intentDatas.get(4), o5 = intentDatas.get(5), o6 = intentDatas.get(6);
        if(o1 != null) {
            this.targetSourceFilter4LatestChatting = (TargetSourceFilter4LatestChatting)o1;
        }
        if(o2 != null) {
            this.targetSourceFilter4Friend = (TargetSourceFilter4Friend)o2;
        }
        if(o3 != null) {
            this.targetSourceFilter4Group = (TargetSourceFilter4Group)o3;
        }
        if(o4 != null) {
            this.targetSourceFilter4GroupMembers = (TargetSourceFilter4GroupMember)o4;
        }

        if(o5 != null) {
            this.extraObjFromItent = (Serializable) o5;
        }
        if(o6 != null) {
            this.gidFromItent = (String) o6;
        }
    }

    // 界面恢复到前台时
    protected void onResume()
    {
        super.onResume();

        // 强制要求每次进来都更新列表（从而保证当数据更新后能及时刷新最新的显示）
        groupListAdapter.notifyDataSetChanged();
    }

    @Override
    protected void initViews(Bundle savedInstanceState)
    {
        //设定自定义标题栏（设定此值即意味着开启自定义标题栏的使用，必须要在setContentView前设定）
        customeTitleBarResId = R.id.target_choose_list_view_titleBar;
        //养成良好习惯：首先设置主layout，确保后绪的操作中使用到的组件都可以被find到
        setContentView(R.layout.target_choose_list);

        radioButtonsContainer = findViewById(R.id.target_choose_list_view_radioButonsContainer);
        latestChattingRadio = findViewById(R.id.target_choose_list_view_latestChattingRb);
        friendRadio = findViewById(R.id.target_choose_list_view_friendsRb);
        groupRadio = findViewById(R.id.target_choose_list_view_groupsRb);
        groupMemberRadio = findViewById(R.id.target_choose_list_view_groupMemberRb);

        // 各UI组件
        addGroupLL = findViewById(R.id.target_choose_list_view_addGroupLL);
        // 标题栏按钮实例
        btnOK = this.getCustomeTitleBar().getRightGeneralButton();
        // 设置标题栏按钮的ui样式
        GroupMemberActivity.setTextButtonStyleForTitle(this, btnOK);
        // 设置ok按钮的初始状态
        _setOkButtonEnable(false);

        // 列表及列表的adapter
        groupListView = findViewById(R.id.target_choose_list_listView);
        // 对列表对象进行相关初始化
        this._initRecyclerView();

        // 如果没有设置目标源类型，则直接退出当前界面
        if(!supportedLatestChattingTargetSource && !supportedFriendTargetSource
                && !supportedGroupTargetSource && !supportedGroupMembersTargetSource) {
            WidgetUtils.showWithDialog(this, $$(R.string.general_prompt), i18n(R.string.target_choose_activity_no_surpported_source_type, this.supportedTargetSource));
            finish();
        }

        // 仅设置目标数据源为"最近聊天"时
        if(this.supportedTargetSource == TargetSource.latestChatting) {
            this.setTitle(i18n(R.string.target_choose_activity_selecte_some, this.latestChattingRadio.getText()));
            this.btnOK.setVisibility(View.VISIBLE);
            this.showCheckBox = true;
            this.singleSelection = true;
            this.radioButtonsContainer.setVisibility(View.GONE);
        }
        // 仅设置目标数据源为"好友"时
        else if(this.supportedTargetSource == TargetSource.friend) {
            this.setTitle(i18n(R.string.target_choose_activity_selecte_some, this.friendRadio.getText()));
            this.btnOK.setVisibility(View.VISIBLE);
            this.showCheckBox = true;
            this.singleSelection = true;
            this.radioButtonsContainer.setVisibility(View.GONE);
        }
        // 仅设置目标数据源为"群聊"时
        else if(this.supportedTargetSource == TargetSource.group){
            this.setTitle(i18n(R.string.target_choose_activity_selecte_some, this.groupRadio.getText()));
            this.btnOK.setVisibility(View.VISIBLE);
            this.showCheckBox = true;
            this.singleSelection = true;
            this.radioButtonsContainer.setVisibility(View.GONE);
        }
        // 仅设置目标数据源为"群成员"时
        else if(this.supportedTargetSource == TargetSource.groupMember){
            this.setTitle(i18n(R.string.target_choose_activity_selecte_some, this.groupMemberRadio.getText()));
            this.btnOK.setVisibility(View.VISIBLE);
            this.showCheckBox = true;
            this.singleSelection = true;
            this.radioButtonsContainer.setVisibility(View.GONE);
        }
        // 已设置多种目标数据源时
        else {
            this.setTitle($$(R.string.target_choose_activity_selecte_target));
            this.btnOK.setVisibility(View.VISIBLE);
            this.showCheckBox = true;
            this.singleSelection = true;
            this.radioButtonsContainer.setVisibility(View.VISIBLE);
        }

        this.setLoadDataOnCreate(false);

        // 界面显示后默认选中第一个，并加载其对应的数据（因无法通过setChecked触发它的OnCheckedChange，所以只能代码显示调用loadData了）
        if(supportedLatestChattingTargetSource) {
            latestChattingRadio.setChecked(true);
            // 加载对应源数据类型的数据
            loadData(String.valueOf(TargetSource.latestChatting));
        } else if(supportedFriendTargetSource) {
            friendRadio.setChecked(true);
            // 加载对应源数据类型的数据
            loadData(String.valueOf(TargetSource.friend));
        } else if(supportedGroupTargetSource) {
            groupRadio.setChecked(true);
            // 加载对应源数据类型的数据
            loadData(String.valueOf(TargetSource.group));
        } else if(supportedGroupMembersTargetSource) {
            groupMemberRadio.setChecked(true);
            // 加载对应源数据类型的数据
            loadData(String.valueOf(TargetSource.groupMember));
        }
    }

    private void _initRecyclerView()
    {
        // 使RecyclerView保持固定的大小,这样会提高RecyclerView的性能
        groupListView.setHasFixedSize(true);

        // 设置分割线（使用官方的一个默认实现，不然自已来画就太烦了）
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
        dividerItemDecoration.setDrawable(ContextCompat.getDrawable(this, R.drawable.user_choose_recycleview_divider));
        groupListView.addItemDecoration(dividerItemDecoration);

        // 设置线性布局管理器
        groupListView.setLayoutManager(new LinearLayoutManager(this));
        // 实例化Adapter
        groupListAdapter = new RecyclerViewLinearAdapter(this, null);
        // 设置Adapter
        groupListView.setAdapter(groupListAdapter);
        // 强制刷新显示（目的是触发内容改变并通知观察者）
        groupListAdapter.notifyDataSetChanged();
    }

    /**
     * 本方法由父类的onCreate()调用，子类可在此方法中为各UI功能组件增加事件临听。
     */
    @Override
    protected void initListeners()
    {
        latestChattingRadio.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if(isChecked) {
                // 加载对应源数据类型的数据
                loadData(false, String.valueOf(TargetSource.latestChatting));
            }
        });
        friendRadio.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if(isChecked) {
                // 加载对应源数据类型的数据
                loadData(false, String.valueOf(TargetSource.friend));
            }
        });
        groupRadio.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if(isChecked) {
                // 加载对应源数据类型的数据
                loadData(false, String.valueOf(TargetSource.group));
            }
        });
        groupMemberRadio.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if(isChecked) {
                // 加载对应源数据类型的数据
                loadData(true, String.valueOf(TargetSource.groupMember));
            }
        });

        // 确认按钮事件处理
        btnOK.setOnClickListener(v -> {
            TargetEntity ue = getSingleSelectedUser();
            if (ue != null) {

                Log.i(TAG, "【目标选择】选择完成，id=" + ue.getTargetId() + ", name=" + ue.getTargetName());

                // 再调置回调数据
                Intent intent = new Intent();
                intent.putExtra("selected_user", ue);
                intent.putExtra("extra_obj", extraObjFromItent);
                setResult(RESULT_OK, intent);

                finish();
            } else {
                WidgetUtils.showWithDialog(self(), $$(R.string.general_prompt), $$(R.string.target_choose_activity_selecte_target_empty));
            }
        });
    }

    /**
     * 获得单选模式下被选中的用户.
     *
     * @return
     */
    private TargetEntity getSingleSelectedUser() {
        TargetEntity retGme = null;
        for (TargetEntity gme : this.groupListAdapter.getListData()) {
            if (gme.isSelected()) {
                retGme = gme;
                break;
            }
        }
        return retGme;
    }

    /**
     * 获得当前选中的行。
     *
     * @return
     */
    private ArrayList<TargetEntity> getSelectedItems() {
        ArrayList<TargetEntity> items = new ArrayList<>();
        for (TargetEntity gme : this.groupListAdapter.getListData()) {
            if (gme.isSelected()) {
                items.add(gme);
            }
        }
        return items;
    }

    /**
     * 返回选中的行数。
     *
     * @return
     */
    public int getSelectedCount()
    {
        int cnt = 0;
        for(TargetEntity gme : this.groupListAdapter.getListData()) {
            if(gme.isSelected()) {
                cnt += 1;
            }
        }
        return cnt;
    }

    /**
     * 重置确认为初始状态：不可点击、文字内容显示为"确定"、以及按钮的UI样式为半透明效果。
     */
    private void _resetOkButton()
    {
        // 设置标题栏保存按钮的可用与禁用时样式
        GroupMemberActivity.setTextButtonEnableForTitle(this, this.btnOK, false);
        this.btnOK.setText($$(R.string.general_ok));
    }

    /**
     * 决置确认按钮的可用性。
     *
     * @param enabled
     */
    private void _setOkButtonEnable(boolean enabled)
    {
        if(enabled) {
            // 设置标题栏保存按钮的可用与禁用时样式
            GroupMemberActivity.setTextButtonEnableForTitle(this, this.btnOK, true);
        } else {
            _resetOkButton();
        }
    }

    /**
     * 设置确认按钮上的选中数量，并根据选中数据量决定按钮是否可点击。
     *
     * @param selectedCount
     */
    private void setOkButtonForSelected(int selectedCount)
    {
        if(selectedCount > 0) {
            _setOkButtonEnable(true);
            if(this.singleSelection)
                this.btnOK.setText($$(R.string.general_ok));
            else
                this.btnOK.setText($$(R.string.general_ok)+"("+selectedCount+")");
        } else {
            _setOkButtonEnable(false);
        }
    }

    /**
     * 本方法默认被父类的loadData调用，用于异步刷新界面数据.
     *
     * @param params loadData中传进来的参数，本类中该参数没有被用到
     */
    @Override
    protected DataFromServer queryData(String... params)
    {
        long t = System.currentTimeMillis();

        int targetSource = CommonUtils.getIntValue(params[0], -1);
        DataFromServer dfs = new DataFromServer();

        if(targetSource != -1){
            ArrayList<TargetEntity> memberList = new ArrayList<>();
            // 加载"最近聊天"数据（数据来源于首页"消息"列表）
            if(targetSource == TargetSource.latestChatting){
                ArrayListObservable<AlarmDto> alarmDatas = imc().getAlarmsProvider().getAlarmsData();
                if(alarmDatas != null && alarmDatas.getDataList().size() > 0) {
                    for (AlarmDto ad : alarmDatas.getDataList()) {
                        if(targetSourceFilter4LatestChatting != null){
                            // 如果过滤器的过滤条件判断结果为"不允许"，则跳过该条数据，以便继续循环遍历余下的数据
                            if(!targetSourceFilter4LatestChatting.allow(ad)) {
                                continue;
                            }
                        }

                        TargetEntity m = constructFromLatestChatting(ad);
                        if(m != null)
                            memberList.add(m);
                    }
                }

                // 将组织好的数据放入DataFromServer对象，refreshToView(..)方法中将能直接拿到
                dfs.setReturnValue(memberList);
                dfs.setSuccess(true);
            }
            // 加载"好友"数据（数据来源于"好友"列表）
            else if(targetSource == TargetSource.friend) {
                // 我的好友列表原始数据
                ArrayListObservable<RosterElementEntity> myRoster = imc().getFriendsListProvider().getRosterData(this, false);
                if (myRoster != null && myRoster.getDataList().size() > 0) {
                    for (RosterElementEntity ree : myRoster.getDataList()) {
                        if(targetSourceFilter4Friend != null){
                            // 如果过滤器的过滤条件判断结果为"不允许"，则跳过该条数据，以便继续循环遍历余下的数据
                            if(!targetSourceFilter4Friend.allow(ree)) {
                                continue;
                            }
                        }

                        TargetEntity m = constructFromRosterElement(ree);
                        if(m != null)
                            memberList.add(m);
                    }
                }

                // 将组织好的数据放入DataFromServer对象，refreshToView(..)方法中将能直接拿到
                dfs.setReturnValue(memberList);
                dfs.setSuccess(true);
            }
            // 加载"群聊"数据（数据来源于"群聊"列表）
            else if(targetSource == TargetSource.group) {
                // 读取原始群列表数据
                ArrayListObservable<GroupEntity> groupsData = imc().getGroupsProvider().getGroupsListData(null, false);
                if (groupsData != null && groupsData.getDataList().size() > 0) {
                    for (GroupEntity ge : groupsData.getDataList()) {
                        if(targetSourceFilter4Group != null){
                            // 如果过滤器的过滤条件判断结果为"不允许"，则跳过该条数据，以便继续循环遍历余下的数据
                            if(!targetSourceFilter4Group.allow(ge)) {
                                continue;
                            }
                        }

                        TargetEntity m = constructFromGroupEntity(ge);
                        if(m != null)
                            memberList.add(m);
                    }
                }

                // 将组织好的数据放入DataFromServer对象，refreshToView(..)方法中将能直接拿到
                dfs.setReturnValue(memberList);
                dfs.setSuccess(true);
            }
            // 加载"群成员"数据（数据来源于"群成员"列表）
            else if(targetSource == TargetSource.groupMember) {
                // 首次是从服务端读取群成员列表
                dfs = HttpRestHelper.submitGetGroupMembersListFromServer(gidFromItent);
                if(dfs.isSuccess()) {
                    // 群成员列表原始数据
                    ArrayList<GroupMemberEntity> members = HttpRestHelper.parseGetGroupMembersListFromServer((String)dfs.getReturnValue());
                    if (members != null && members.size() > 0) {
                        for (GroupMemberEntity ge : members) {
                            if(targetSourceFilter4GroupMembers != null){
                                // 如果过滤器的过滤条件判断结果为"不允许"，则跳过该条数据，以便继续循环遍历余下的数据
                                if(!targetSourceFilter4GroupMembers.allow(ge)) {
                                    continue;
                                }
                            }

                            TargetEntity m = constructFromGroupMember(ge);
                            if(m != null)
                                memberList.add(m);
                        }
                    }

                    /*
                       构建"@所有人"item数据：
                       目前 TargetSource.groupMember 暂时是专用于"@"功能时选择被"@"的成员时，暂时为了简化代码，
                       "@所有人"这个选项只能在 TargetChooseActivity 另用代码写死，暂时就不考虑"@"功能之外使用了，特此说明！
                    */
                    // 如果本地用户是该群的群主
                    if(GroupsProvider.isThisGroupOwner(gidFromItent)) {
                        memberList.add(0, constructAtAll());
                    }

                    dfs.setReturnValue(memberList);
                }
            }
        }

        Log.i(TAG, "数据加载完成，本次耗时："+(System.currentTimeMillis() - t)+"毫秒。");

        return dfs;
    }

    /**
     * 本方法的作用是把queryData里返回的数据放到UI上显示.
     */
    @Override
    protected void refreshToView(Object dataToView)
    {
        // 准备列表数据
        staticListData = (dataToView == null? new ArrayList<>(): (ArrayList<TargetEntity>) dataToView);
        // 设置列表数据
        groupListAdapter.setListData(staticListData);
        // 强制刷新列表的UI显示（目的是触发内容改变并通知观察者）
        groupListAdapter.notifyDataSetChanged();
    }

    private TargetEntity constructFromLatestChatting(AlarmDto ad) {
        if(ad != null) {
            int targetChatType = -1;
            switch (ad.getAlarmType()){
                case AlarmType.guestChat:
                    targetChatType = ChatType.CHAT_TYPE_GUEST$CHAT;
                    break;
                case AlarmType.friendChat:
                    targetChatType = ChatType.CHAT_TYPE_FREIDN$CHAT;
                    break;
                case AlarmType.groupChat:
                    targetChatType = ChatType.CHAT_TYPE_GROUP$CHAT;
                    break;
            }

            TargetEntity m = new TargetEntity();
            m.setTargetChatType(targetChatType);
            m.setTargetId(ad.getDataId());
            m.setTargetName(ad.getTitle());
            m.setTargetOtherInfo(ad.getAlarmContent());
            m.setUserAvatarFileName(ad.getExtraString1());

            m.setSelected(false);

            return m;
        }
        return null;
    }

    private TargetEntity constructFromRosterElement(RosterElementEntity ree) {
        if(ree != null) {
            TargetEntity m = new TargetEntity();
            m.setTargetChatType(ChatType.CHAT_TYPE_FREIDN$CHAT);
            m.setTargetId(ree.getUser_uid());
            m.setTargetName(ree.getNickname());
            m.setTargetOtherInfo("ID："+ree.getUser_uid());
            m.setUserAvatarFileName(ree.getUserAvatarFileName());

            m.setSelected(false);

            return m;
        }
        return null;
    }

    private TargetEntity constructFromGroupEntity(GroupEntity ge) {
        if(ge != null) {
            TargetEntity m = new TargetEntity();
            m.setTargetChatType(ChatType.CHAT_TYPE_GROUP$CHAT);
            m.setTargetId(ge.getG_id());
            m.setTargetName(ge.getG_name());
            m.setTargetOtherInfo(i18n(R.string.target_choose_activity_group_create_time, ge.getCreate_time()));//+"，当前"+ge.getG_member_count()+"人");

            m.setSelected(false);

            return m;
        }
        return null;
    }

    private TargetEntity constructFromGroupMember(GroupMemberEntity ge) {
        if(ge != null) {
            int targetChatType = -1;
            if(imc().getFriendsListProvider().isUserInRoster2(ge.getUser_uid())) {
                targetChatType = ChatType.CHAT_TYPE_FREIDN$CHAT;
            } else {
                targetChatType = ChatType.CHAT_TYPE_GUEST$CHAT;
            }

            TargetEntity m = new TargetEntity();
            m.setTargetChatType(targetChatType);
            m.setTargetId(ge.getUser_uid());
            m.setTargetName(GroupsProvider.getNickNameInGroup(ge.getNickname(), ge.getNickname_ingroup())); // 由于昵称的复杂性：原昵称、群内昵称、好友备注等多重情况，为了简化逻辑，此处跟微信一样，被@者任何时候都用他原本的昵称
            m.setTargetOtherInfo("ID："+ge.getUser_uid());
            m.setUserAvatarFileName(ge.getUserAvatarFileName());

            m.setSelected(false);

            return m;
        }
        return null;
    }

    /**
     * 构建"@所有人"item数据。
     *
     * 目前 TargetSource.groupMember 暂时是专用于"@"功能时选择被"@"的成员时，暂时为了简化代码，
     * "@所有人"这个选项只能在 TargetChooseActivity 另用代码写死，暂时就不考虑"@"功能之外使用了，特此说明！
     *
     * @return
     */
    private TargetEntity constructAtAll() {
        int targetChatType = TargetEntity.TARGET_CHAT_TYPE_FOR_AT_ALL;

        TargetEntity m = new TargetEntity();
        m.setTargetChatType(targetChatType);
        m.setTargetId("0");// "@"功能中定义的被"@"uid为"0"时即表示"@"所有人
        m.setTargetName($$(R.string.target_choose_activity_at_all));
        m.setTargetOtherInfo($$(R.string.target_choose_activity_group_owner_permision));

        m.setSelected(false);

        return m;
    }


    //-------------------------------------------------------------------------------- 内部类

    /**
     * 数据列表RecyclerView的Adapter实现类。
     */
    private class RecyclerViewLinearAdapter extends ARecyclerViewAdapter<TargetEntity>
    {
        private ContentOnClickListener contentOnClickListener = new ContentOnClickListener();
        private HeadIconOnClickListener headIconOnClickListener = new HeadIconOnClickListener();

        public RecyclerViewLinearAdapter(Activity context, OnItemClickListener onItemClickListener)
        {
            super(context, R.layout.target_choose_list_item, onItemClickListener);
        }

        /**
         * 列表adapter数据结构创建方法.
         * 子类可覆盖此方法用以实现自已的数据结构.
         *
         * @return
         */
        @Override
        protected List<TargetEntity> createListData()
        {
            return staticListData;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            return new LinearViewHolder(layoutInflater.inflate(itemResId, parent,false));
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position)
        {
            // 别忘了调用父类方法
            super.onBindViewHolder(viewHolder, position);

            //----------------------------------------------------------------------------- （1）组件填值
            // 正在操作的viewHolder对象
            LinearViewHolder holder = (LinearViewHolder)viewHolder;
            // 正在操作的列表行的数据集
            final TargetEntity rowData = listData.get(position);

            // 是否显示选择框
            if(showCheckBox)
                holder.cbSelect.setVisibility(View.VISIBLE);
            else
                holder.cbSelect.setVisibility(View.GONE);

            // 给标签设置值，以供用户查看
            holder.viewName.setText(rowData.getTargetName());
            holder.viewId.setText(rowData.getTargetOtherInfo());
            holder.cbSelect.setChecked(rowData.isSelected());

            // 当前显示的是“最近聊天”tab时，尝试对进行表情显示处理
            if(latestChattingRadio.isChecked() && !CommonUtils.isStringEmpty(rowData.getTargetOtherInfo(), true)) {
                // FFF emoji图片表情转换
                SpannableString ss = EmojiUtil.replaceEmoticons(self(), rowData.getTargetOtherInfo(), 50, 50, DynamicDrawableSpan.ALIGN_BOTTOM);
                holder.viewId.setText(ss);
            }

            // 以下代码，解决Glide在RecycleView中图片错位或重复显示问题
            Glide.with(context).clear(holder.viewAvatar);// 解决方法2


            //----------------------------------------------------------------------------- （2）异步加载头像
            if(rowData.getTargetChatType() != TargetEntity.TARGET_CHAT_TYPE_FOR_AT_ALL) {
                holder.viewId.setTextColor(getResources().getColor(R.color.gray_dark_for_text));

                boolean isLatestChattingChecked = latestChattingRadio.isChecked();
                if (rowData.getTargetChatType() == ChatType.CHAT_TYPE_GUEST$CHAT) {
                    int defaultAvatarResId = (isLatestChattingChecked ? R.drawable.default_avatar_for_contact_40dp_21pxround : R.drawable.default_avatar_yuan_50_3x);
                    // clear完成后设置默认占位图，确保图片显示不出现Glide导致的错位问题
                    holder.viewAvatar.setImageResource(defaultAvatarResId);
                    if (rowData.getTargetId() != null) {
                        // 加载用户头像(不从sd卡读取缓存（dontDiskCache=true将确保app启动后首次加载时能从网络加载一次）)
                        ImageCacheLoader.loadAvatarImgWithGlide(getContext(), rowData.getTargetId(), rowData.getUserAvatarFileName()
                                , holder.viewAvatar
                                , isLatestChattingChecked ? 7 : 25 // 圆角单位是dp，（1dp相当于xxhdpi下的3像素）
                                , defaultAvatarResId, true, false);
                    }
                } else if (rowData.getTargetChatType() == ChatType.CHAT_TYPE_FREIDN$CHAT) {
                    int defaultAvatarResId = (isLatestChattingChecked ? R.drawable.default_avatar_for_contact_40dp_21pxround : R.drawable.default_avatar_yuan_50_3x);
                    // clear完成后设置默认占位图，确保图片显示不出现Glide导致的错位问题
                    holder.viewAvatar.setImageResource(defaultAvatarResId);

                    String friendUid = rowData.getTargetId();
                    // 用户的头像文件名（这个文件名目前仅用于Glide缓存图片时作为signature字段使用）
                    String fileNameForUserAvatar = null;
                    if (friendUid != null) {
                        // 优先从好友数据中读取对方头像文件名，确保文件名是最新的
                        final RosterElementEntity friendRee = imc().getFriendsListProvider().getFriendInfoByUid2(friendUid);
                        if (friendRee != null) {
                            fileNameForUserAvatar = friendRee.getUserAvatarFileName();
                            // 群成员数据的话，就不要用好友备注来显示了
                            if(!groupMemberRadio.isChecked()) {
                                // 优先使用好友列表中的昵称，确保首页"消息"列表中显示的好友聊天item标题能尽可能保持最新数据 @since 7.3
                                holder.viewName.setText(friendRee.getNickNameWithRemark());
                            }
                        }

                        boolean dontDiskCache = false;
                        // 该字段为空可能是该用户没有设置头像，也可能是有可能是对方已把"我"删除，因而对方不在我
                        // 的好友列表里了，所以好友数据不存在，头像文件名也就取不到了，这种情况取头像时，就把它当陌生人聊
                        // 天模式去取头像，即dontDiskCache为true——确保相同url情况下至少app重启后能强行拉取一次最新头像
                        if (CommonUtils.isStringEmpty(fileNameForUserAvatar, true)) {
                            dontDiskCache = true;
                        }
                        // 加载用户头像(有头像文件名fileNameForUserAvatar作为Glide加载时的signature，可以保证在好友更改头像后，能及时加载到最新图片)
                        ImageCacheLoader.loadAvatarImgWithGlide(getContext(), friendUid, fileNameForUserAvatar
                                , holder.viewAvatar
                                , isLatestChattingChecked ? 7 : 25 // 圆角单位是dp，（1dp相当于xxhdpi下的3像素）
                                , defaultAvatarResId, dontDiskCache, false);
                    }
                } else if (rowData.getTargetChatType() == ChatType.CHAT_TYPE_GROUP$CHAT) {
                    // clear完成后设置默认占位图，确保图片显示不出现Glide导致的错位问题
                    holder.viewAvatar.setImageResource(R.drawable.groupchat_groups_icon_default_r21px);
                    if (rowData.getTargetId() != null) {
                        // 加载群头像
                        ImageCacheLoader.loadGroupImgWithGlide(Glide.with(getContext()), rowData.getTargetId(), holder.viewAvatar, 7, false, R.drawable.groupchat_groups_icon_default_r21px);// 圆角单位是dp，（相当于xxhdpi下的21像素）
                    }
                }

                // 点击头像的事件处理
                holder.viewAvatar.setOnClickListener(v -> {
                    headIconOnClickListener.setContentData(rowData);
                    headIconOnClickListener.onClick(v);
                });
            } else {
                // 针对"@所有人"item的说明：
                //  目前 TargetSource.groupMember 暂时是专用于"@"功能时选择被"@"的成员时，暂时为了简化代码，
                // "@所有人"这个选项只能在 TargetChooseActivity 另用代码写死，暂时就不考虑"@"功能之外使用了，特此说明！
                holder.viewId.setTextColor(getResources().getColor(R.color.common_list_light_red_for_text));
                holder.viewAvatar.setImageResource(R.drawable.contact_list_header_my_groups_ico_45dp_y);
            }


            //----------------------------------------------------------------------------- （3）增加点击事件处理
            holder.layoutOfGotochat.setOnClickListener(v -> {
                contentOnClickListener.setContentData(rowData);
                contentOnClickListener.onClick(v);
            });
        }

        /**
         * 根据RecyclerView内容的变动，来决定无数据时的UI内容显示。
         */
        protected void dataSetChanged()
        {
            if(this.getItemCount() > 0) {
                addGroupLL.setVisibility(View.GONE);
                groupListView.setVisibility(View.VISIBLE);
            }
            // 没有数据时显示显示ui
            else {
                addGroupLL.setVisibility(View.VISIBLE);
                groupListView.setVisibility(View.GONE);
            }

            // 设置确认按钮的显示
            setOkButtonForSelected(getSelectedCount());
        }

        private void deSelectedAll()
        {
            for(TargetEntity gme : this.getListData())
            {
                gme.setSelected(false);
            }
        }

        /**
         * ViewHolder实现类。
         */
        class LinearViewHolder extends RecyclerView.ViewHolder
        {
            //声明layout_linearrv_item布局控件的变量

            private ViewGroup layoutOfGotochat = null;
            private TextView viewName = null;
            private TextView viewId = null;
            private CheckBox cbSelect = null;
            private ImageView viewAvatar = null;

            public LinearViewHolder(View itemView)
            {
                super(itemView);

                // item里的操作组件实例
                layoutOfGotochat = (ViewGroup) itemView.findViewById(R.id.target_choose_list_item_contentLL);
                viewName = (TextView) itemView.findViewById(R.id.target_choose_list_item_nameView);
                viewId = (TextView) itemView.findViewById(R.id.target_choose_list_item_idView);
                cbSelect = (CheckBox) itemView.findViewById(R.id.target_choose_list_item_selectCb);
                viewAvatar = (ImageView) itemView.findViewById(R.id.target_choose_list_item_imageView);
            }
        }

        /**
         * 点击item事件处理.
         */
        private class ContentOnClickListener implements View.OnClickListener
        {
            private TargetEntity contentData = null;

            public void setContentData(TargetEntity contentData)
            {
                this.contentData = contentData;
            }

            @Override
            public void onClick(View v)
            {
                if (contentData != null)
                {
                    // 支持多选
                    if (!singleSelection) {
                        contentData.setSelected(!contentData.isSelected());
                    }
                    // 支持单选
                    else {
                        // 先取消其它的选中
                        deSelectedAll();
                        // 再选中当前
                        contentData.setSelected(true);
                    }

                    // 并通知刷新列表ui
                    notifyDataSetChanged();
                }
            }
        }

        /**
         * 用户头像点击事件监听器.
         */
        private class HeadIconOnClickListener implements View.OnClickListener
        {
            private TargetEntity contentData = null;

            public void setContentData(TargetEntity contentData)
            {
                this.contentData = contentData;
            }

            @Override
            public void onClick(View v)
            {
                if(contentData != null && contentData.getTargetId() != null) {
                    if(contentData.getTargetChatType() == ChatType.CHAT_TYPE_GROUP$CHAT) {
                        QueryGroupInfo.gotoWatchGroupInfo(self(), contentData.getTargetId(), null);
                    } else {
                        QueryFriendInfo.gotoWatchUserInfo(self(), contentData.getTargetId(), null);
                    }
                }
            }
        }
    }
}
